package cn.topevery.garden.dal.dao.impl;

import cn.topevery.garden.dal.dao.CoreIndicatorsRuleDao;
import cn.topevery.garden.dal.dao.CriterionEvaluationDao;
import cn.topevery.garden.dal.dao.CriterionExpandDao;
import cn.topevery.garden.dal.logic.CriterionDefLogic;
import cn.topevery.garden.entity.po.CoreIndicatorsItem;
import cn.topevery.garden.entity.po.CriterionDef;
import cn.topevery.garden.entity.po.CriterionEvaluation;
import cn.topevery.garden.entity.po.CriterionExpand;
import cn.topevery.garden.entity.query.CriterionEvaluationQuery;
import cn.topevery.garden.entity.vo.CriterionEvaluationVO;
import cn.topevery.garden.framework.base.BaseDaoImpl;
import hw.topevery.basis.entity.po.SysUser;
import hw.topevery.basis.runtime.UserRuntime;
import hw.topevery.framework.db.CommandType;
import hw.topevery.framework.db.entity.DataPager;
import hw.topevery.framework.db.entity.SqlQueryMate;
import hw.topevery.framework.db.entity.SqlUpdateMate;
import hw.topevery.framework.db.enums.ScriptConditionEnum;
import hw.topevery.framework.entity.DbCsp;
import hw.topevery.framework.entity.KeyValue;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 *
 * @author code-generate
 * @date 2022-01-05
 */
@Repository
public class CriterionEvaluationDaoImpl extends BaseDaoImpl<CriterionEvaluation> implements CriterionEvaluationDao {
    @Autowired
    private CriterionExpandDao criterionExpandDao;
    @Autowired
    private CriterionDefLogic criterionDefDao;
    @Autowired
    private CoreIndicatorsRuleDao coreIndicatorsRuleDao;
    @Override
    public <P extends DbCsp> List<CriterionEvaluation> getSearch(P para) {
        return null;
    }

    

    @Override
    public DataPager<CriterionEvaluationVO> listPage(CriterionEvaluationQuery query) {
        String table = "t_criterion_evaluation tce";

        String columns = "tce.*";

        int pageIndex = query.pageIndex - 1;
        int pageSize = query.pageSize;

        SqlQueryMate sqlQueryMate = new SqlQueryMate(table).setColumns(columns).setOrderBy("tce.c_id desc");
        sqlQueryMate
                .where(true, "tce.c_db_status", ScriptConditionEnum.Eq, 0)
        ;

        return getDataPager(sqlQueryMate, pageSize, pageIndex, CriterionEvaluationVO.class);
    }

    @Override
    public CriterionEvaluation getEntityByColumn(String key,String value){
        KeyValue<String> map=new KeyValue<>();
        map.key=key;
        map.value=value;
        return getEntityByColumnEqValue(map);
    }

    @Override
    public CriterionEvaluation getByCriterionIdAndMapId(String criterionId, String mapId) {
        String table = "t_criterion_evaluation evaluation\n" +
                "       join t_criterion_def def on evaluation.c_criterion_id = def.c_criterion_id";
        String columns = "evaluation.*, def.c_is_expand";
        SqlQueryMate sqlQueryMate = new SqlQueryMate(table).setColumns(columns).setOrderBy("evaluation.c_year desc");
        sqlQueryMate.where(StringUtils.isNotBlank(criterionId), "evaluation.c_criterion_id", ScriptConditionEnum.Eq, criterionId)
                .where(StringUtils.isNotBlank(mapId), "evaluation.c_map_id", ScriptConditionEnum.Eq, mapId);
        return selectOne(sqlQueryMate, CriterionEvaluation.class);
    }

    @Override
    public void evaluation(List<CriterionEvaluation> evaluationList, Integer userId) {
        SysUser user = UserRuntime.getSysUser();
        CriterionEvaluation evaluation;
        Integer relationType = null;
        CriterionEvaluation lastEvaluation = evaluationList.get(evaluationList.size() - 1);
        if (lastEvaluation.getRelationType() != null) {
            relationType = lastEvaluation.getRelationType();
        }
        int reachFlag = 0;
        for (int i = evaluationList.size() - 1; i >=0; i--) {
            evaluation = evaluationList.get(i);
            if (evaluation.getIsExpand() == 0) {
                List<CriterionExpand> list = criterionExpandDao.getListByCriterionId(evaluation.getCriterionId());
                if (list != null && !list.isEmpty()) {
                    if(evaluation.getRealValue() != null) {
                        switch (list.get(0).getOperator()) {
                            case 1:
                                if (evaluation.getRealValue() >= list.get(0).getValue()) {
                                    evaluation.setIsReach(0);
                                } else {
                                    evaluation.setIsReach(1);
                                }
                                break;
                            case 2:
                                if (evaluation.getRealValue() <= list.get(0).getValue()) {
                                    evaluation.setIsReach(0);
                                } else {
                                    evaluation.setIsReach(1);
                                }
                                break;
                            case 3:
                                if (evaluation.getRealValue() > list.get(0).getValue()) {
                                    evaluation.setIsReach(0);
                                } else {
                                    evaluation.setIsReach(1);
                                }
                                break;
                            case 4:
                                if (evaluation.getRealValue() < list.get(0).getValue()) {
                                    evaluation.setIsReach(0);
                                } else {
                                    evaluation.setIsReach(1);
                                }
                                break;
                            case 5:
                                if (evaluation.getRealValue().equals(list.get(0).getValue())) {
                                    evaluation.setIsReach(0);
                                } else {
                                    evaluation.setIsReach(1);
                                }
                                break;
                            default:
                                evaluation.setIsReach(1);
                        }
                    } else {
                        evaluation.setIsReach(1);
                    }
                }
            } else {
                evaluation.setIsReach(evaluation.getRealValue() == 1.00f ? 0 : 1);
            }
            //关联关系的最终评价结果不要影响单个结果 加一个最终结果的字段
            if (relationType != null) {
                if (evaluation.getIsReach() == 0) {
                    reachFlag += 1;
                } else {
                    reachFlag -= 1;
                }
            }
            boolean isReach = evaluation.getIsReach() == 0;
            if (i == 0) {
                if (relationType != null) {
                    if (relationType == 1) {
                        if (reachFlag == evaluationList.size()) {//与关系
//                            evaluation.setIsReach(0);
                            isReach = true;
                        } else {
//                            evaluation.setIsReach(1);
                            isReach = false;
                        }
                    } else {
                        if (reachFlag > -evaluationList.size()) {//或关系
//                            evaluation.setIsReach(0);
                            isReach = true;
                        } else {
//                            evaluation.setIsReach(1);
                            isReach = false;
                        }
                    }
                }
            }
            evaluation.setIsRealReach(isReach ? 0 : 1);
            boolean isChange = true;
            boolean isNew = true;
            SqlQueryMate sqlQueryMate = new SqlQueryMate("t_criterion_evaluation tce").setColumns("tce.*");
            sqlQueryMate.where(true, "c_db_status", ScriptConditionEnum.Eq, 0)
                    .where(StringUtils.isNotBlank(evaluation.getCriterionId()), "c_criterion_id", ScriptConditionEnum.Eq, evaluation.getCriterionId())
                    .where(StringUtils.isNotBlank(evaluation.getMapId()), "c_map_id", ScriptConditionEnum.Eq, evaluation.getMapId())
                    .where(StringUtils.isNotBlank(evaluation.getYear()), "c_year", ScriptConditionEnum.Eq, evaluation.getYear());
            CriterionEvaluation oldEvaluation = selectOne(sqlQueryMate, CriterionEvaluation.class);
            if (oldEvaluation != null) {
                if (evaluation.getIsRealReach().equals(oldEvaluation.getIsRealReach())) {
                    isChange = false;
                }
                isNew = false;
                SqlUpdateMate sqlUpdateMate = new SqlUpdateMate("t_criterion_evaluation");
                sqlUpdateMate
                        .setColumnValue(evaluation.getRealValue()!=null, "c_real_value", evaluation.getRealValue())
                        .setColumnValue(StringUtils.isNotBlank(evaluation.getUpdateId()), "c_db_last_update_id", evaluation.getUpdateId())
                        .setColumnValue(true, "c_update_date", evaluation.getUpdateDate())
                        .setColumnValue(true, "c_is_real_reach", evaluation.getIsRealReach())
                        .setColumnValue(true, "c_is_reach", evaluation.getIsReach())
                        .where(true, "c_db_status", ScriptConditionEnum.Eq, 0)
                        .where(true, "c_criterion_id", ScriptConditionEnum.Eq, evaluation.getCriterionId())
                        .where(true, "c_map_id", ScriptConditionEnum.Eq, evaluation.getMapId())
                        .where(true, "c_year", ScriptConditionEnum.Eq, evaluation.getYear());
                run(sqlUpdateMate.getSql(), CommandType.Text, dbCommand -> {
                        sqlUpdateMate.getParameters().forEach(dbCommand::addParameter);
                        dbCommand.executeNonQuery();
                });
            } else {
                isChange = false;
                evaluation.setDbStatus(false);
                evaluation.setUpdateDate(LocalDateTime.now());
                evaluation.setUpdateId(user.userId);
                insert(user.userId, evaluation);
            }
            if (i == 0) {
                updateParentEvaluationCount(evaluation, isReach, isChange, isNew);
            }
        }

    }

        private void updateParentEvaluationCount(CriterionEvaluation evaluation, boolean isReach, boolean isChange, boolean isNew) {
        SqlQueryMate sqlQueryMate = new SqlQueryMate("t_criterion_evaluation tce").setColumns("tce.*");
        sqlQueryMate.where(true, "c_db_status", ScriptConditionEnum.Eq, 0)
                .where(StringUtils.isNotBlank(evaluation.getCriterionPid()), "c_criterion_id", ScriptConditionEnum.Eq, evaluation.getCriterionPid())
                .where(StringUtils.isNotBlank(evaluation.getYear()), "c_year", ScriptConditionEnum.Eq, evaluation.getYear())
                .where(StringUtils.isNotBlank(evaluation.getMapId()), "c_map_id", ScriptConditionEnum.Eq, evaluation.getMapId());
        CriterionEvaluation parentEvaluation = selectOne(sqlQueryMate, CriterionEvaluation.class);
        if (parentEvaluation != null) {
            Integer reachCount = parentEvaluation.getReachCount();
            if (isChange) {
                reachCount = isReach ? reachCount + 1 : reachCount - 1;
            }
            if (isNew) {
                reachCount = isReach ? reachCount + 1 : reachCount;
            }
            SqlUpdateMate sqlUpdateMate = new SqlUpdateMate("t_criterion_evaluation_show");
            sqlUpdateMate
                    .setColumnValue(true, "c_evaluation_count", isNew ? parentEvaluation.getEvaluationCount() +1 : parentEvaluation.getEvaluationCount())
                    .setColumnValue(true, "c_reach_count", reachCount)
                    .setColumnValue(StringUtils.isNotBlank(evaluation.getUpdateId()), "c_db_last_update_id", evaluation.getUpdateId())
                    .setColumnValue(true, "c_update_date", evaluation.getUpdateDate())
                    .where(true, "c_db_status", ScriptConditionEnum.Eq, 0)
                    .where(true, "c_criterion_id", ScriptConditionEnum.Eq, parentEvaluation.getCriterionId())
                    .where(true, "c_map_id", ScriptConditionEnum.Eq, parentEvaluation.getMapId())
                    .where(true, "c_year", ScriptConditionEnum.Eq, parentEvaluation.getYear());
            run(sqlQueryMate.getSql(), CommandType.Text, dbCommand -> {
                sqlQueryMate.getParameters().forEach(dbCommand::addParameter);
                dbCommand.executeNonQuery();
            });
        } else {
            parentEvaluation = new CriterionEvaluation();
            CriterionDef criterionDef = criterionDefDao.getOneById(evaluation.getCriterionPid());
            parentEvaluation.setCriterionId(evaluation.getCriterionPid());
            parentEvaluation.setCriterionPid(criterionDef.getCriterionPid());
            parentEvaluation.setDbStatus(false);
            parentEvaluation.setUpdateId(evaluation.getUpdateId());
            parentEvaluation.setUpdateDate(LocalDateTime.now());
            parentEvaluation.setMapId(evaluation.getMapId());
            parentEvaluation.setMapName(evaluation.getMapName());
            parentEvaluation.setYear(evaluation.getYear());
            parentEvaluation.setEvaluationCount(1);
            parentEvaluation.setReachCount(isReach ? 1 : 0);
            insert(UserRuntime.getSysUser().userId, parentEvaluation);
        }
        if (!"00000000-0000-0000-0000-000000000000".equals(parentEvaluation.getCriterionPid())) {
            updateParentEvaluationCount(parentEvaluation, isReach, isChange, isNew);
        }
    }

    @Override
    public List<CriterionEvaluation> getListByCriterionId(String criterionId) {
        SqlQueryMate sqlQueryMate = new SqlQueryMate("t_criterion_evaluation tce").setColumns("tce.*");
        sqlQueryMate.where(true, "c_db_status", ScriptConditionEnum.Eq, 0)
                .where(StringUtils.isNotBlank(criterionId), "c_criterion_id", ScriptConditionEnum.Eq, criterionId);
        return selectList(sqlQueryMate, CriterionEvaluation.class);
    }

    @Override
    public void updateCountWhenPartakeChange(String criterionId, Integer flag) {
        String sql = "update t_criterion_evaluation t\n" +
                "        set t.c_evaluation_count = t.c_evaluation_count + :flag,\n" +
                "            t.c_reach_count      = t.c_reach_count + :flag\n" +
                "        where t.c_criterion_id = :criterionId";
        run(sql, CommandType.Text, dbCommand -> {
            dbCommand.addInParameter("flag", flag);
            dbCommand.addInParameter("criterionId", criterionId);
            dbCommand.executeNonQuery();
        });
    }

    @Override
    public void yearForNewData() {
        String sql = "INSERT INTO t_criterion_evaluation(c_criterion_id, c_criterion_pid, c_map_id, c_map_name, c_dept_id, c_dept_name, c_numerator, c_denominator, c_real_value, c_is_reach, c_is_real_reach, c_year, c_evaluation_count, c_reach_count, c_update_id, c_update_date, c_db_status)\n" +
                "        select c_criterion_id, c_criterion_pid, c_map_id, c_map_name, c_dept_id, c_dept_name, c_numerator, c_denominator, c_real_value, c_is_reach, c_is_real_reach, YEAR(NOW()), c_evaluation_count, c_reach_count, c_update_id, c_update_date, c_db_status from t_criterion_evaluation t where t.c_year = YEAR(NOW()) - 1 and t.c_db_status = 0";
        run(sql, CommandType.Text, dbCommand -> {
            dbCommand.executeNonResultSet();
        });
    }

    @Override
    public List<CriterionEvaluation> getRelationListByCriterionIdAndMapId(List<CriterionDef> criterionList, String mapId) {
        List<CriterionEvaluation> evaluationList = new ArrayList<>();
        CriterionEvaluation evaluation;
        for (CriterionDef criterionDef : criterionList) {
            SqlQueryMate sqlQueryMate = new SqlQueryMate("t_criterion_evaluation tce").setColumns("tce.*").setOrderBy("c_year desc");
            sqlQueryMate.where(true, "c_db_status", ScriptConditionEnum.Eq, 0)
                    .where(StringUtils.isNotBlank(criterionDef.getCriterionId()), "c_criterion_id", ScriptConditionEnum.Eq, criterionDef.getCriterionId())
                    .where(StringUtils.isNotBlank(mapId), "c_map_id", ScriptConditionEnum.Eq, mapId);
            evaluation = selectOne(sqlQueryMate, CriterionEvaluation.class);
            if (evaluation == null) {
                evaluation = new CriterionEvaluation();
                evaluation.setCriterionId(criterionDef.getCriterionId());
                evaluation.setCriterionPid(criterionDef.getCriterionPid());
                evaluation.setYear(String.valueOf(LocalDateTime.now().getYear()));
                evaluation.setMapId(mapId);
                if (criterionDef.getIsExpand() != 0) {
                    evaluation.setRealValue(1.00f);//不用计算的默认显示达标
                }
            }
            if (StringUtils.isNotBlank(criterionDef.getExpression())) {
                List<CoreIndicatorsItem> res = coreIndicatorsRuleDao.info(criterionDef.getExpression());
                evaluation.setExpression(res.get(0).getName() + "/" + res.get(1).getName());
            }
            if (criterionDef.getIsExpand() == 0) {
                List<CriterionExpand> list = criterionExpandDao.getListByCriterionId(criterionDef.getCriterionId());
                evaluation.setUnit(list.get(0).getUnit());
            }
            evaluation.setRelationType(criterionDef.getRelationType());
            evaluation.setCriterionName(criterionDef.getCriterionName());
            evaluation.setIsExpand(criterionDef.getIsExpand());
            evaluationList.add(evaluation);
        }
        return evaluationList;
    }
}
